#include "binanceklineclient.h"
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QEventLoop>

BinanceKLineClient::BinanceKLineClient(QObject *parent)
    : QObject(parent)
    , m_webSocket(new QWebSocket())
    , m_reconnectTimer(new QTimer(this))
    , m_isConnected(false)
{
    setupWebSocket();

    // 设置重连定时器
    m_reconnectTimer->setInterval(5000); // 5秒重连
    m_reconnectTimer->setSingleShot(true);
    connect(m_reconnectTimer, &QTimer::timeout, this, &BinanceKLineClient::reconnect);
}

BinanceKLineClient::~BinanceKLineClient()
{
    disconnectFromBinance();
    m_webSocket->deleteLater();
}

void BinanceKLineClient::setupWebSocket()
{
    // 连接信号槽
    connect(m_webSocket, &QWebSocket::connected, this, &BinanceKLineClient::onConnected);
    connect(m_webSocket, &QWebSocket::disconnected, this, &BinanceKLineClient::onDisconnected);
    connect(m_webSocket, &QWebSocket::textMessageReceived,
            this, &BinanceKLineClient::onTextMessageReceived);
    connect(m_webSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
            this, &BinanceKLineClient::onError);
}

void BinanceKLineClient::connectToBinance(const QString& symbol, const QString& interval)
{
    m_currentSymbol = symbol.toLower();
    m_currentInterval = interval.toLower();

    QString streamName = m_currentSymbol + "@kline_" + m_currentInterval;
    QString url = QString("wss://stream.binance.com:9443/ws/%1").arg(streamName);

    qDebug() << "Connecting to:" << url;
    m_webSocket->open(QUrl(url));
}

void BinanceKLineClient::disconnectFromBinance()
{
    m_reconnectTimer->stop();
    if (m_webSocket->state() == QAbstractSocket::ConnectedState) {
        m_webSocket->close();
    }
}

void BinanceKLineClient::subscribeKLine(const QString& symbol, const QString& interval)
{
    QString streamName = symbol.toLower() + "@kline_" + interval.toLower();

    QJsonObject subscribeMsg;
    subscribeMsg["method"] = "SUBSCRIBE";
    subscribeMsg["params"] = QJsonArray{streamName};
    subscribeMsg["id"] = 1;

    QJsonDocument doc(subscribeMsg);
    m_webSocket->sendTextMessage(doc.toJson(QJsonDocument::Compact));
}

void BinanceKLineClient::unsubscribeKLine(const QString& symbol, const QString& interval)
{
    QString streamName = symbol.toLower() + "@kline_" + interval.toLower();

    QJsonObject unsubscribeMsg;
    unsubscribeMsg["method"] = "UNSUBSCRIBE";
    unsubscribeMsg["params"] = QJsonArray{streamName};
    unsubscribeMsg["id"] = 1;

    QJsonDocument doc(unsubscribeMsg);
    m_webSocket->sendTextMessage(doc.toJson(QJsonDocument::Compact));
}

void BinanceKLineClient::fetchHistoricalData(const QString& symbol, const QString& interval, int limit)
{
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);

    QString url = QString("https://api.binance.com/api/v3/klines?symbol=%1&interval=%2&limit=%3")
                      .arg(symbol.toUpper())
                      .arg(interval)
                      .arg(limit);

    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

    QNetworkReply *reply = manager->get(request);

    connect(reply, &QNetworkReply::finished, this, [=]() {
        if (reply->error() == QNetworkReply::NoError) {
            QByteArray data = reply->readAll();
            QJsonDocument doc = QJsonDocument::fromJson(data);
            QJsonArray klineArray = doc.array();

            QVector<KLineData> historicalData;
            historicalData.reserve(klineArray.size());

            for (const QJsonValue &value : klineArray) {
                QJsonArray arr = value.toArray();
                KLineData kline = parseKLineArray(arr, symbol);
                historicalData.append(kline);
            }

            emit historicalDataReceived(historicalData);
            qDebug() << "Historical data fetched:" << historicalData.size() << "records";
        } else {
            emit errorOccurred("Failed to fetch historical data: " + reply->errorString());
        }

        reply->deleteLater();
        manager->deleteLater();
    });
}

void BinanceKLineClient::onConnected()
{
    m_isConnected = true;
    m_reconnectTimer->stop();
    qDebug() << "Connected to Binance WebSocket";
    emit connected();

    // 自动订阅当前交易对
    if (!m_currentSymbol.isEmpty() && !m_currentInterval.isEmpty()) {
        subscribeKLine(m_currentSymbol, m_currentInterval);
    }
}

void BinanceKLineClient::onDisconnected()
{
    m_isConnected = false;
    qDebug() << "Disconnected from Binance WebSocket";
    emit disconnected();

    // 尝试重连
    if (!m_currentSymbol.isEmpty()) {
        m_reconnectTimer->start();
    }
}

void BinanceKLineClient::onTextMessageReceived(const QString& message)
{
    QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
    if (doc.isNull()) {
        qDebug() << "Invalid JSON message:" << message;
        return;
    }

    QJsonObject obj = doc.object();

    // 检查是否是K线数据
    if (obj.contains("e") && obj["e"].toString() == "kline") {
        parseKLineMessage(obj);
    }
    // 处理订阅确认消息
    else if (obj.contains("result") || obj.contains("id")) {
        qDebug() << "Subscription response:" << message;
    }
}

void BinanceKLineClient::parseKLineMessage(const QJsonObject& obj)
{
    QJsonObject klineObj = obj["k"].toObject();

    KLineData data;
    data.symbol = klineObj["s"].toString();
    data.timestamp = klineObj["t"].toVariant().toLongLong();
    data.closeTime = klineObj["T"].toVariant().toLongLong();
    data.open = klineObj["o"].toString().toDouble();
    data.high = klineObj["h"].toString().toDouble();
    data.low = klineObj["l"].toString().toDouble();
    data.close = klineObj["c"].toString().toDouble();
    data.volume = klineObj["v"].toString().toDouble();
    data.quoteVolume = klineObj["q"].toString().toDouble();
    data.trades = klineObj["n"].toInt();

    // 检查K线是否结束
    bool isKlineClosed = klineObj["x"].toBool();

    if (isKlineClosed) {
        // K线结束，添加到数据列表
        updateKLineData(data);
        emit kLineDataReceived(data);
        qDebug() << "KLine Closed:" << data.toString();
    } else {
        // K线更新
        m_latestKline = data;
        emit kLineUpdated(data);
    }
}

KLineData BinanceKLineClient::parseKLineArray(const QJsonArray& arr, const QString& symbol)
{
    KLineData data;
    data.symbol = symbol;
    data.timestamp = arr[0].toVariant().toLongLong();
    data.open = arr[1].toString().toDouble();
    data.high = arr[2].toString().toDouble();
    data.low = arr[3].toString().toDouble();
    data.close = arr[4].toString().toDouble();
    data.volume = arr[5].toString().toDouble();
    data.closeTime = arr[6].toVariant().toLongLong();
    data.quoteVolume = arr[7].toString().toDouble();
    data.trades = arr[8].toInt();

    return data;
}

void BinanceKLineClient::updateKLineData(const KLineData& newData)
{
    // 查找是否已存在相同时间戳的K线
    bool found = false;
    for (int i = 0; i < m_klineData.size(); ++i) {
        if (m_klineData[i].timestamp == newData.timestamp) {
            m_klineData[i] = newData;
            found = true;
            break;
        }
    }

    // 如果不存在，添加到列表
    if (!found) {
        m_klineData.append(newData);

        // 限制数据量，保持最近1000条
        if (m_klineData.size() > 1000) {
            m_klineData.removeFirst();
        }
    }

    m_latestKline = newData;
}

void BinanceKLineClient::onError(QAbstractSocket::SocketError error)
{
    QString errorMsg = QString("WebSocket error: %1").arg(m_webSocket->errorString());
    qDebug() << errorMsg;
    emit errorOccurred(errorMsg);
}

void BinanceKLineClient::reconnect()
{
    qDebug() << "Attempting to reconnect...";
    if (!m_currentSymbol.isEmpty() && !m_currentInterval.isEmpty()) {
        connectToBinance(m_currentSymbol, m_currentInterval);
    }
}
